package com.cxf.ws.util;

import java.io.ByteArrayOutputStream;
import java.io.IOException;

import javax.xml.namespace.QName;
import javax.xml.rpc.handler.Handler;
import javax.xml.rpc.handler.HandlerInfo;
import javax.xml.rpc.handler.soap.SOAPMessageContext;
import javax.xml.soap.SOAPMessage;

import org.apache.commons.lang.StringEscapeUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.cmbc.cos.cbs.wsclient.WsClientConfig;

public class LogSOAPMessageRPCHandler implements Handler {

    private static Logger                    log        = LoggerFactory.getLogger(LogSOAPMessageRPCHandler.class);
    private static ThreadLocal<StringBuffer> logContext = new ThreadLocal<StringBuffer>() {

                                                            @Override
                                                            protected StringBuffer initialValue() {
                                                                return new StringBuffer();
                                                            }
                                                        };

    private static ThreadLocal<Long> timeContext = new ThreadLocal<Long>(){
    	
    	@Override
        protected Long initialValue() {
            return new Long(0);
        }
    };
                                                     
    @Override
    public void destroy() {

    }

    @Override
    public QName[] getHeaders() {
        return null;
    }

    @Override
    public boolean handleFault(javax.xml.rpc.handler.MessageContext ctx) {
        log.error(replaceLogText());
        logContext.remove();
        return true;
    }

    @Override
    public boolean handleRequest(javax.xml.rpc.handler.MessageContext ctx) {
        logXmlContext(true, (SOAPMessageContext) ctx);
        return true;
    }

    @Override
    public boolean handleResponse(javax.xml.rpc.handler.MessageContext ctx) {
        logXmlContext(false, (SOAPMessageContext) ctx);
        return true;
    }

    private void logXmlContext(boolean isRequest, SOAPMessageContext ctx) {
        if (WsClientConfig.isTraceSOAP()) {

            SOAPMessage message = ctx.getMessage();
            if (isRequest) {
            	if(timeContext.get() == null){
            		timeContext.set(new Long(System.currentTimeMillis()));
            	}else{
            		timeContext.set(System.currentTimeMillis());
            	}
                logText("\nrequest  : ");
                logText(soapMessageToXml(message));
            }
            else {
                logText("\nresponse : ");
                logText(soapMessageToXml(message));
                if(timeContext.get() != null){
                	logText("\n Call costs:" + (System.currentTimeMillis() - timeContext.get()));
                }
                log.info(replaceLogText());
                logContext.remove();
            }
        }
    }

    private String replaceLogText() {
        String text = logContext.get().toString();
        for (String replacement : WsClientConfig.getReplacements()) {
            text = text.replaceAll(replacement, "$1content has been repalced$3");
        }
        return text;
    }

    private void logText(String text) {
        if (logContext.get() == null) {
            logContext.set(new StringBuffer(text));
        }
        else {
            logContext.get().append(text);
        }
    }

    private String soapMessageToXml(SOAPMessage message) {
        ByteArrayOutputStream bos = null;

        if (message != null) {
            try {
                bos = new ByteArrayOutputStream();
                message.writeTo(bos);
                bos.flush();
                String result = new String(bos.toByteArray(), "UTF-8");
                return StringEscapeUtils.unescapeHtml(result);
            }
            catch (Exception e) {
                log.error("soapMessageToXml error", e);
            }
            finally {
                if (bos != null) {
                    try {
                        bos.close();
                    }
                    catch (IOException e) {
                    }
                }
            }
        }
        return "";
    }

    @Override
    public void init(HandlerInfo arg0) {

    }

}
